#include "pfc.h"

#ifdef _UNIX
#include <stdarg.h>
#endif 
//implementations of deprecated string_printf methods, with a pragma to disable warnings when they reference other deprecated methods.

#pragma warning(disable:4996)

//辅助函数
// 输出单个字符
char out_char(int i)
{
    switch (i)
    {
    case 0:
        return '0';
        break;
    case 1:
        return '1';
        break;
    case 2:
        return '2';
        break;
    case 3:
        return '3';
        break;
    case 4:
        return '4';
        break;
    case 5:
        return '5';
        break;
    case 6:
        return '6';
        break;
    case 7:
        return '7';
        break;
    case 8:
        return '8';
        break;
    case 9:
        return '9';
        break;
    case 10:
        return 'A';
        break;
    case 11:
        return 'B';
        break;
    case 12:
        return 'C';
        break;
    case 13:
        return 'D';
        break;
    case 14:
        return 'E';
        break;
    case 15:
        return 'F';
        break;
    default:
        return NULL;
        break;
    }
}

// int to ansi string
void itoa(int v, char* str, int base)
{
    int i=0;
    bool is_negative = false;
    if (v<0)
    {
        is_negative = true;
        v = -v;
    }

    while ((v/base)!=0)
    {
        str[i++]= out_char(v%base);
        v = v/base;
    }
    if (v!=0)
        str[i++]= out_char(v);
    if (is_negative)
    {
        str[i++]='-';
    }
    char c;
    for (int j=0;j<i/2;j++)
    {
        c = str[j];
        str[j]=str[i-1-j];
        str[i-1-j]=  c;
    }
    str[i]='\0';
}

void ultoa(unsigned long v, char* str, int base)
{
    int i=0;

    while ((v/base)!=0)
    {
        str[i++]= out_char(v%base);
        v = v/base;
    }
    if (v!=0)
        str[i++]= out_char(v);

    char c;
    for (int j=0;j<i/2;j++)
    {
        c = str[j];
        str[j]=str[i-1-j];
        str[i-1-j]=  c;
    }
    str[i]='\0';
}

void i64toa(int64_t v, char* str, int base)
{
    int i=0;
    bool is_negative = false;
    if (v<0)
    {
        is_negative = true;
        v = -v;
    }

    while ((v/base)!=0)
    {
        str[i++]= out_char(v%base);
        v = v/base;
    }
    if (v!=0)
        str[i++]= out_char(v);
    if (is_negative)
    {
        str[i++]='-';
    }
    char c;
    for (int j=0;j<i/2;j++)
    {
        c = str[j];
        str[j]=str[i-1-j];
        str[i-1-j]=  c;
    }
    str[i]='\0';
}

void ui64toa(uint64_t v, char* str, int base)
{
    int i=0;

    while ((v/base)!=0)
    {
        str[i++]= out_char(v%base);
        v = v/base;
    }
    if (v!=0)
        str[i++]= out_char(v);

    char c;
    for (int j=0;j<i/2;j++)
    {
        c = str[j];
        str[j]=str[i-1-j];
        str[i-1-j]=  c;
    }
    str[i]='\0';
}

void i64tow(int64_t v, wchar_t* str, int base)
{
    int i=0;
    bool is_negative = false;
    if (v<0)
    {
        is_negative = true;
        v = -v;
    }

    while ((v/base)!=0)
    {
        str[i++]= out_char(v%base);
        v = v/base;
    }
    if (v!=0)
        str[i++]= out_char(v);
    if (is_negative)
    {
        str[i++]='-';
    }
    char c;
    for (int j=0;j<i/2;j++)
    {
        c = str[j];
        str[j]=str[i-1-j];
        str[i-1-j]=  c;
    }
    str[i]='\0';
}

void ui64tow(uint64_t v, wchar_t* str, int base)
{
    int i=0;

    while ((v/base)!=0)
    {
        str[i++]= v%base;
        v = v/base;
    }
    if (v!=0)
        str[i++]= out_char(v);

    wchar_t c;
    for (int j=0;j<i/2;j++)
    {
        c = str[j];
        str[j]=str[i-1-j];
        str[i-1-j]=  c;
    }
    str[i]='\0';
}
namespace pfc
{

    void string_printf::run(const char * fmt,va_list list)
    {
        g_run(*this,fmt,list);
    }

    string_printf_va::string_printf_va(const char * fmt,va_list list)
    {
        string_printf::g_run(*this,fmt,list);
    }

    void string_printf::g_run(string_base & out,const char * fmt,va_list list)
    {
        out.reset();
        while (*fmt)
        {
            if (*fmt=='%')
            {
                fmt++;
                if (*fmt=='%')
                {
                    out.add_char('%');
                    fmt++;
                }
                else
                {
                    bool force_sign = false;
                    if (*fmt=='+')
                    {
                        force_sign = true;
                        fmt++;
                    }
                    char padchar = (*fmt == '0') ? '0' : ' ';
                    t_size pad = 0;
                    while (*fmt>='0' && *fmt<='9')
                    {
                        pad = pad * 10 + (*fmt - '0');
                        fmt++;
                    }

                    if (*fmt=='s' || *fmt=='S')
                    {
                        const char * ptr = va_arg(list,const char*);
                        t_size len = strlen(ptr);
                        if (pad>len) out.add_chars(padchar,pad-len);
                        out.add_string(ptr);
                        fmt++;

                    }
                    else if (*fmt=='i' || *fmt=='I' || *fmt=='d' || *fmt=='D')
                    {
                        char temp[8*sizeof(int)];
                        int val = va_arg(list,int);
                        if (force_sign && val>0) out.add_char('+');
#ifdef _WINDOWS
                        _itoa_s(val,temp,10);
#elif defined(_UNIX)
                        itoa(val,temp,10);
#else
#error PORTME
#endif
                        t_size len = strlen(temp);
                        if (pad>len) out.add_chars(padchar,pad-len);
                        out.add_string(temp);
                        fmt++;
                    }
                    else if (*fmt=='u' || *fmt=='U')
                    {
                        char temp[8*sizeof(int)];
                        int val = va_arg(list,int);
                        if (force_sign && val>0) out.add_char('+');

#ifdef _WINDOWS
                        _ultoa_s(val,temp,16);
#elif defined(_UNIX)
                        ultoa(val,temp,16);
#else
#error PORTME
#endif
                        t_size len = strlen(temp);
                        if (pad>len) out.add_chars(padchar,pad-len);
                        out.add_string(temp);
                        fmt++;
                    }
                    else if (*fmt=='x' || *fmt=='X')
                    {
                        char temp[8*sizeof(int)];
                        int val = va_arg(list,int);
                        if (force_sign && val>0) out.add_char('+');
#ifdef _WINDOWS
                        _ultoa_s(val,temp,16);
#elif defined(_UNIX)
                        ultoa(val,temp,16);
#else
#error PORTME
#endif
                        if (*fmt=='X')
                        {
                            char * t = temp;
                            while (*t)
                            {
                                if (*t>='a' && *t<='z')
                                    *t += 'A' - 'a';
                                t++;
                            }
                        }
                        t_size len = strlen(temp);
                        if (pad>len) out.add_chars(padchar,pad-len);
                        out.add_string(temp);
                        fmt++;
                    }
                    else if (*fmt=='c' || *fmt=='C')
                    {
                        out.add_char(va_arg(list,int));
                        fmt++;
                    }
                }
            }
            else
            {
                out.add_char(*(fmt++));
            }
        }
    }

    string_printf::string_printf(const char * fmt,...)
    {
        va_list list;
        va_start(list,fmt);
        run(fmt,list);
        va_end(list);
    }


}
